<template>
<div class="el-transfer-panel">
    <p class="el-transfer-panel__header">
      <el-checkbox
        v-model="allChecked"
        @change="handleAllCheckedChange"
        :indeterminate="isIndeterminate">
        {{ title }}
        <span>{{ checkedSummary }}</span>
      </el-checkbox>
    </p>
    <div :class="['el-transfer-panel__body', hasFooter ? 'is-with-footer' : '']">
      <el-input
        class="el-transfer-panel__filter"
        v-model="query"
        size="small"
        :placeholder="placeholder"
        @mouseenter.native="inputHover = true"
        @mouseleave.native="inputHover = false"
        v-if="filterable && !customFilter">
        <i slot="prefix"
          :class="['el-input__icon', 'el-icon-' + inputIcon]"
          @click="clearQuery"
        ></i>
      </el-input>
      <slot v-else name="leftCustomFilter"></slot>
      <el-checkbox-group
        v-model="checked"
        v-show="!hasNoMatch && data.length > 0"
        v-infinite-scroll="loadMore"
        :class="{ 'is-filterable': filterable }"
        class="el-transfer-panel__list">
        <el-checkbox
          class="el-transfer-panel__item"
          :label="item[keyProp]"
          :disabled="item[disabledProp]"
          :key="item[keyProp]"
          v-for="item in showData">
          <option-content :option="item"></option-content>
        </el-checkbox>
      </el-checkbox-group>
      <p
        class="el-transfer-panel__empty"
        v-show="hasNoMatch">无匹配数据</p>
      <p
        class="el-transfer-panel__empty"
        v-show="data.length === 0 && !hasNoMatch">无数据</p>
    </div>
    <p class="el-transfer-panel__footer" v-if="hasFooter">
      <slot></slot>
    </p>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import OptionContent from './option-content.vue'
@Component({
  name: 'V7TransferPanel',
  components: {
    OptionContent
  }
})
export default class TransferPanel extends Vue {
  @Prop({ default: () => [] }) private data?: any
  @Prop() private renderContent?: any
  @Prop({ default: () => '' }) private placeholder?: string
  @Prop() private title?: string
  @Prop() private filterMethod?: any
  @Prop() private customFilterMethod?: any
  @Prop({ default: () => ({}) }) private leftcustomFilterData?: any
  @Prop() private format?: any
  @Prop(Boolean) private filterable: boolean|undefined
  @Prop(Boolean) private customFilter: boolean|undefined
  @Prop() private defaultChecked?: []
  @Prop() private props?: any
  @Prop({ default: () => 20 }) private loadDataNum?: number

  private componentName = 'V7TransferPanel'
  private checked: any = []
  private allChecked: any = false
  private query: string = ''
  private inputHover: boolean = false
  private checkChangeByUser: boolean = true
  private showData: any = []

  @Watch('checked')
  private checkedChange (val: [], oldVal: []) {
    this.updateAllChecked();
    if (this.checkChangeByUser) {
      const movedKeys = val.concat(oldVal).filter(v => val.indexOf(v) === -1 || oldVal.indexOf(v) === -1);
      this.$emit('checked-change', val, movedKeys);
    } else {
      this.$emit('checked-change', val);
      this.checkChangeByUser = true;
    }
  }

  @Watch('data')
  private dataChange () {
    const checked: any = [];
    const filteredDataKeys = this.filteredData.map((item: any) => item[this.keyProp]);
    this.checked.forEach((item: any) => {
      if (filteredDataKeys.indexOf(item) > -1) {
        checked.push(item);
      }
    });
    this.checkChangeByUser = false;
    this.checked = checked;
  }

  @Watch('checkableData')
  private checkAbleDataChange () {
    this.updateAllChecked();
  }

  @Watch('defaultChecked', { immediate: true })
  private defaultCheckedChange (val: [], oldVal: []) {
    if (oldVal && val.length === oldVal.length && val.every(item => oldVal.indexOf(item) > -1)) {
      return
    }
    const checked: any = [];
    const checkableDataKeys = this.checkableData.map((item: any) => item[this.keyProp]);
    val.forEach(item => {
      if (checkableDataKeys.indexOf(item) > -1) {
        checked.push(item);
      }
    });
    this.checkChangeByUser = false;
    this.checked = checked;
  }

  @Watch('filteredData')
  private filteredDataChange () {
    const length = this.showData.length
    this.showData = this.filteredData.slice(0, length)
    this.loadMore()
  }

  get filteredData () {
    return this.data.filter((item: any) => {
      if (typeof this.filterMethod === 'function') {
        return this.filterMethod(this.query, item);
      } else if (this.customFilter) {
        return this.customFilterMethod(this.customQuery, item)
      } else {
        const label = item[this.labelProp] || item[this.keyProp].toString();
        return label.toLowerCase().indexOf(this.query.toLowerCase()) > -1;
      }
    });
  }

  get checkableData () {
    return this.filteredData.filter((item: any) => !item[this.disabledProp]);
  }

  // public getValue (val) {
  //   this.$set(this, 'customQuery', val)
  //   console.log(this.customQuery)
  // }

  public customQuery = ''

  get checkedSummary () {
    const checkedLength = this.checked.length;
    const dataLength = this.data.length;
    const { noChecked, hasChecked } = this.format;
    if (noChecked && hasChecked) {
      return checkedLength > 0
        ? hasChecked.replace(/\${checked}/g, checkedLength).replace(/\${total}/g, dataLength)
        : noChecked.replace(/\${total}/g, dataLength);
    } else {
      return `${checkedLength}/${dataLength}`;
    }
  }

  get isIndeterminate () {
    const checkedLength = this.checked.length;
    return checkedLength > 0 && checkedLength < this.checkableData.length;
  }

  get hasNoMatch () {
    if (this.customFilter) {
      return this.filteredData.length === 0;
    } else {
      return this.query.length > 0 && this.filteredData.length === 0;
    }
  }

  get inputIcon () {
    return this.query.length > 0 && this.inputHover
      ? 'circle-close'
      : 'search';
  }

  get labelProp () {
    return this.props.label || 'label';
  }

  get keyProp () {
    return this.props.key || 'key';
  }

  get disabledProp () {
    return this.props.disabled || 'disabled';
  }

  get hasFooter () {
    return !!this.$slots.default;
  }

  private loadMore () {
    const len = this.showData.length
    const allLength = this.filteredData.length
    if (len < allLength) {
      this.showData = [...this.showData, ...this.filteredData.slice(len, len + this.loadDataNum)]
    }
  }

  private updateAllChecked () {
    const checkableDataKeys = {}
    this.checkableData.map((item: any) => {
      checkableDataKeys[item[this.keyProp]] = true
    })
    this.allChecked = Object.keys(checkableDataKeys).length > 0 && this.checked.length > 0 && this.checked.every((item: any) => checkableDataKeys[item])
  }

  private handleAllCheckedChange (value: any) {
    this.checked = value ? this.checkableData.map((item: any) => item[this.keyProp]) : [];
  }

  private clearQuery () {
    if (this.inputIcon === 'circle-close') {
      this.query = '';
    }
  }
}
</script>
